﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UCL.Powersource.Analysis;
using UCL.Powersource.TFS;

namespace UCL.Powersource
{
    public class StatisticManagerQueueItem : UCL.Powersource.IStatisticManagerQueueItem
    {
        public QueuedItemStatus Status { get; private set; }
        public IStatistic Statistic { get; private set; }
        public ITfsTeamProjectConfiguration TfsTeamProjectConfiguration { get; private set; }
        public ITimeFrame TimeFrame { get; private set; }
        public IRemoteBuilderQueueItem RemoteBuilderQueueItem { get; internal set; }
        public bool ForceRecalculate { get; private set; }
        public Exception ComputationException { get; private set; }
        public Boolean HasTerminatedNormally { get; private set; }
        public IStatisticManagerQueue Owner { get { return _Owner; } }
        internal void SetForceRecalculateForInactive(bool forceRecalculate)
        {
            if (this.ForceRecalculate == forceRecalculate) return;
            if (Status == QueuedItemStatus.Activated) throw new InvalidOperationException(string.Format("You cannot change FroceRecalculate for already active item {0}", this.ToString()));
            this.ForceRecalculate = forceRecalculate;
        }

        private StatisticManagerQueue _Owner;

        internal string GetActionString()
        {
            string stat = "#NULL";
            string team = "#NULL";
            string tf = "#NULL";
            if (this.Statistic != null) stat = this.Statistic.Label;
            if (this.TfsTeamProjectConfiguration != null) team = this.TfsTeamProjectConfiguration.Label;
            if (this.TimeFrame != null) tf = this.TimeFrame.Label;
            return string.Format("{0} for {1} at {2} - {3}",stat,team,tf,this.Status.ToString());
        }

        public event EventHandler<QueuedItemChangedEventArgs> Changed;
        public event EventHandler Completed;

        internal StatisticManagerQueueItem(StatisticManagerQueue owner, IStatistic statistic, ITfsTeamProjectConfiguration pr, ITimeFrame tf, bool forceRecalculate)
        {
            Statistic = statistic;
            TfsTeamProjectConfiguration = pr;
            TimeFrame = tf;
            ForceRecalculate = forceRecalculate;
            Status = QueuedItemStatus.New;
            _Owner = owner;
        }

        

        internal void Finish(Exception exc, bool NormallyFinished)
        {
            lock (_Owner)
            {
                ComputationException = exc;
                this.HasTerminatedNormally = NormallyFinished;

                if (Status != QueuedItemStatus.Activated)
                    throw new InvalidOperationException(string.Format("Cannot finish calculation for project {0} if its status is {1} and not {2}", TfsTeamProjectConfiguration.UniqueName, Status, QueuedItemStatus.Activated.ToString()));

                Status = QueuedItemStatus.Finished;
            }

            RaiseChange(QueuedItemStatus.Finished);
        }

        private void RaiseChange(QueuedItemStatus newStatus)
        {

            if (Changed != null)
            {
                Changed(this, new QueuedItemChangedEventArgs(newStatus));
            }
            if (newStatus == QueuedItemStatus.Finished && Completed != null) Completed(this, EventArgs.Empty);
        }

        internal void Enqueued()
        {
            lock (_Owner)
            {
                if (this.Status != QueuedItemStatus.New) throw new InvalidOperationException(String.Format("An attempt to change status for {0} to Enqueued failed. Current status is {1}, but it must be {2}", this.ToString(), this, Status, QueuedItemStatus.New));
                this.Status = QueuedItemStatus.Enqueued;
            }
            RaiseChange(QueuedItemStatus.Enqueued);
        }

        internal void Activated()
        {
            lock (_Owner)
            {
                if (this.Status != QueuedItemStatus.Enqueued) throw new InvalidOperationException(String.Format("An attempt to change status for {0} to Activated failed. Current status is {1}, but it must be {2}", this.ToString(), this, Status, QueuedItemStatus.Enqueued));
                this.Status = QueuedItemStatus.Activated;
            }
            RaiseChange(QueuedItemStatus.Activated);
        }
        public override string ToString()
        {
            var IbuildDetail = "#NULL";
            if (RemoteBuilderQueueItem != null)
            {
                IbuildDetail = RemoteBuilderQueueItem.ToString();
            }
            if (this.TfsTeamProjectConfiguration != null && this.TimeFrame != null)
            {
                return string.Format("SMQI: {0} [{1},{2}][{3}]-{4}", this.Statistic.Name, this.TfsTeamProjectConfiguration.Label, this.TimeFrame.Label, this.Status, IbuildDetail);
            }
            else
                return string.Format("SMQI: {0} [Unitilized][{1}] - {2}", this.Statistic.Name, this.Status, IbuildDetail);
        }


        public Guid CurrentBatchQueueGuid { get; private set; }
        internal void SetBatchQueueGuidForEnqueued(Guid BatchQueueGuid)
        {
            if (CurrentBatchQueueGuid == null)
            {
                CurrentBatchQueueGuid = BatchQueueGuid;
            }
            else
            {
                if (Status ==QueuedItemStatus.Activated )
                    throw new InvalidOperationException("You cannot change batch queue guid while items is active!");
                CurrentBatchQueueGuid = BatchQueueGuid;
            }
        }
    }
}
